﻿using System.ComponentModel;
using System.Runtime.Serialization;

using SharpGL.SceneGraph.Transformations;

namespace SharpGL.SceneGraph.Effects
{
    /// <summary>
    /// An ArcBallTransformation is an effect that pushes an arcball transformation 
    /// onto the stack.
    /// </summary>
    [TypeConverter(typeof(System.ComponentModel.ExpandableObjectConverter))]
    [DataContract(/*IsReference = true, */Name = "ArcBallTransformationEffect", Namespace = "SharpGL.SceneGraph")]
    public class ArcBallTransformationEffect : Effect
    {
        #region Private Consts

        private static readonly string defaultName = "Arc ball transrotmation effect";

        #endregion Private Consts

        #region Private Fields

        /// <summary>
        /// The arcball.
        /// </summary>
        [DataMember()]
        private ArcBallTransformation arcBallTransformation = new ArcBallTransformation();

        #endregion Private Fields

        #region Private Methods

        private void OnArcBallTransformationPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            NotifyPropertyChanged(sender.GetType() + "." + e.PropertyName);
        }

        #endregion Private Methods

        #region Protected Methods

        protected override void OnDeserialized()
        {
            arcBallTransformation.PropertyChanged += new PropertyChangedEventHandler(OnArcBallTransformationPropertyChanged);
        }

        #endregion Protected Methods

        #region Public Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="ArcBallTransformationEffect"/> class.
        /// </summary>
        public ArcBallTransformationEffect()
        {
            Name = defaultName;
            arcBallTransformation.PropertyChanged += new PropertyChangedEventHandler(OnArcBallTransformationPropertyChanged);
        }

        #endregion Public Constructors

        #region Public Methods

        /// <summary>
        /// Pushes the effect onto the specified parent element.
        /// </summary>
        /// <param name="gl">The OpenGL instance.</param>
        /// <param name="parentElement">The parent element.</param>
        public override void Push(OpenGL gl, SceneElement parentElement)
        {
            if (OpenGL.IsValidContext(gl))
            {
                //  Push the stack.
                gl.PushMatrix();

                //  Perform the transformation.
                if (arcBallTransformation != null)
                    arcBallTransformation.Transform(gl);
            }
        }

        /// <summary>
        /// Pops the specified parent element.
        /// </summary>
        /// <param name="gl">The OpenGL instance.</param>
        /// <param name="parentElement">The parent element.</param>
        public override void Pop(OpenGL gl, SceneElement parentElement)
        {
            if (OpenGL.IsValidContext(gl))
            {
                //  Pop the stack.
                gl.PopMatrix();
            }
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets the arcball transformation.
        /// </summary>
        /// <value>
        /// The arcball transformation.
        /// </value>
        [Description("The ArcBallTransformation."), Category("Effect")]
        public ArcBallTransformation ArcBallTransformation
        {
            get { return arcBallTransformation; }
            set
            {
                if (arcBallTransformation != value)
                {
                    arcBallTransformation.PropertyChanged -= new PropertyChangedEventHandler(OnArcBallTransformationPropertyChanged);

                    if (value == null)
                        arcBallTransformation = new ArcBallTransformation();
                    else
                        arcBallTransformation = value;

                    arcBallTransformation.PropertyChanged += new PropertyChangedEventHandler(OnArcBallTransformationPropertyChanged);

                    NotifyPropertyChanged("ArcBallTransformation");
                }
            }
        }

        #endregion
    }
}
